package com.seleniti.enpareja.controller.ui.base;

import org.ioc.commons.flowcontrol.actioncontroller.ActionController;
import org.ioc.commons.flowcontrol.actioncontroller.ActionHandler;
import org.ioc.commons.flowcontrol.actioncontroller.IsExternalAction;
import org.ioc.commons.flowcontrol.common.Receiver;
import org.ioc.commons.flowcontrol.common.impl.ReceiverWrapper;
import org.ioc.commons.flowcontrol.eventbus.EventBus;
import org.ioc.commons.flowcontrol.eventbus.IsEvent;
import org.ioc.commons.flowcontrol.operationmanager.IsOperation;
import org.ioc.commons.flowcontrol.operationmanager.OperationManager;
import org.ioc.commons.flowcontrol.operationmanager.OperationManagerTrigger;
import org.ioc.commons.ui.IsViewPresenter;
import org.ioc.commons.utils.FormatterLogger;

import com.seleniti.enpareja.controller.common.GlobalData;
import com.seleniti.enpareja.controller.common.domain.LoggedUserInfo;
import com.seleniti.enpareja.controller.common.domain.UserAgent;
import com.seleniti.enpareja.controller.common.exception.EnParejaException;
import com.seleniti.enpareja.controller.model.integration.database.domain.Couple;
import com.seleniti.enpareja.controller.model.integration.database.domain.NotificationType;
import com.seleniti.enpareja.controller.ui.main.AppShell;
import com.seleniti.enpareja.controller.ui.view.EnParejaView;

public abstract class EnParejaViewBasePresenter<D extends EnParejaView<E, O, A>, E extends Enum<? extends IsEvent>, O extends Enum<? extends IsOperation>, A extends Enum<? extends IsExternalAction>>
		extends EnParejaBasePresenter<D, E, O, A> implements IsViewPresenter {

	private static final FormatterLogger logger = FormatterLogger.getLogger(EnParejaViewBasePresenter.class);

//	protected Couple couple;

	protected AppShell shell;

	public EnParejaViewBasePresenter(D display, EventBus<E> eventbus, OperationManager<O> operationManager,
			ActionController<A> actionController) {
		super(display, eventbus, operationManager, actionController);
	}

	@Override
	public void onInitDisplay() {
		super.onInitDisplay();
		this.shell = clientFactory.getShell();
		bindComponents();
	}

	@Override
	public void onActive() {
		/*
		 * Override me
		 */
	}

	@Override
	public void onDeactive() {
		/*
		 * Override me
		 */
	}

//	protected boolean ensureCouple(final String operationDescription, O operation,
//			OperationManagerTrigger<O> operationManager, String... requiredProperties) {
//
//		if (this.couple == null) {
//
//			if (operationManager.isOpPending(operation)) {
//				messageBoxFactory.info("Buscando a tu pareja", "Un momento, estamos comprobando quién es tu pareja...");
//			} else {
//
//				messageBoxFactory.info("Pareja no encontrada", "Comprobando quién es tu pareja...");
//				Receiver<Couple> receiver = new ReceiverAdapter<Couple>() {
//
//					@Override
//					public void success(Couple result) {
//						if (result != null) {
//							messageBoxFactory.info("Pareja encontrada", "Comprobación correcta. Vuelve a intentar {0}",
//									operationDescription.toLowerCase());
//						} else {
//							messageBoxFactory.info("Pareja no encontrada",
//									"No hemos podido determinar quién es tu pareja. ");
//						}
//
//					}
//				};
//				refreshCouple(receiver, operation, operationManager, requiredProperties);
//			}
//		}
//
//		return this.couple != null;
//	}

	protected void refreshCouple(Receiver<Couple> receiver, O operation, OperationManagerTrigger<O> operationManager,
			String... requiredProperties) {
		if (!display.isInitialized()) {
			return;
		}
		logger.info("Refreshing couple...");
		final LoggedUserInfo lui = this.loginController.getLoggedUserInfo();

		String coupleId = lui != null ? lui.getCoupleId() : null;
		if (coupleId != null) {
			logger.info("Getting couple id={0}...", coupleId);
			this.serviceManager.serviceFactory().coupleService().find(coupleId).performing(operation, operationManager)
					.with(requiredProperties).to(new ReceiverWrapper<Couple, Couple>(receiver) {

						@Override
						public void success(Couple result) {
							logger.info("... got couple {0}", result);
							display.couple().setValue(result);
							if (receiver != null) {
								receiver.success(result);
							}
						}

						@SuppressWarnings("incomplete-switch")
						@Override
						public void failure(Throwable failure) {
							EnParejaException epe = exceptionController.fromMessage(EnParejaException.class,
									failure.getMessage());

							if (epe != null && epe.getErrorCode() != null) {
								switch (epe.getErrorCode()) {
								case LOGGIN_REQUIRED:
									logger.error("Login required from server when tried to get couple using LUI={0}",
											lui);
									break;
								// case PASSWORD_ENCRYPTION_FAILURE:
								// break;
								// case PERMISSION_DENIED:
								// break;
								}
							}

							super.failure(failure);
						}

					}).caller(this);
		} else {
			logger.info("no couple id");
		}
	}

	protected void saveCouple(O operation, OperationManagerTrigger<O> operationManager, final boolean refresh) {
		saveCouple(operation, operationManager, refresh, null);
	}

	protected void saveCouple(O operation, OperationManagerTrigger<O> operationManager, final boolean refresh,
			final NotificationType notificateLoggedUserCouple) {
		saveCouple(operation, operationManager, refresh, notificateLoggedUserCouple, null);
	}

	protected void saveCouple(O operation, OperationManagerTrigger<O> operationManager, final boolean refresh,
			final NotificationType notificateLoggedUserCouple, final String extraInfo) {
		saveCouple(operation, operationManager, refresh, notificateLoggedUserCouple, extraInfo, null);
	}

	protected void saveCouple(O operation, OperationManagerTrigger<O> operationManager, final boolean refresh,
			final NotificationType notificateLoggedUserCouple, final String extraInfo, Receiver<String> callback) {
		Couple couple = display.couple().getValue();
		logger.info("Saving couple {0}...", couple);
		serviceManager.serviceFactory().coupleService().save(couple).performing(operation, operationManager)
				.to(new ReceiverWrapper<String, String>(callback) {

					@Override
					public void success(String result) {
						if (refresh) {
							refreshData();
						}

						if (notificateLoggedUserCouple != null) {
							serviceManager.serviceFactory().notificationService()
									.notifyLoggedUserCouple(notificateLoggedUserCouple, extraInfo)
									.caller(EnParejaViewBasePresenter.this);
						}

						if (receiver != null) {
							receiver.success(result);
						}
					}
				}).caller(this);
	}

	protected void refreshData() {
		/*
		 * Override me
		 */
	}

	protected void bindComponents() {
		shell.actionController().bindAction(AppShell.Action.RefreshNow, new ActionHandler<AppShell.Action>() {

			@Override
			public void handleAction(Object sender, com.seleniti.enpareja.controller.ui.main.AppShell.Action action,
					Object... params) {
				refreshData();
			}
		});

	}

	protected void showGoBackButtonIfRequired() {
		UserAgent ua = (UserAgent) this.globalDataController.getGlobalDataValue(GlobalData.UserAgent);

		shell.goBackButtonVisible().setVisible(ua != UserAgent.ANDROID_EMBEDDED_BROWSER);
	}

}
